/*
	Implementation of this object has benefit greatly from..
	http://www.codeproject.com/Articles/225988/A-practical-guide-to-Cplusplus-serialization
*/

#include "GamePlayer.h"

GamePlayer::GamePlayer()
{
	systemUniqueID = IDENTITY_NOT_ESTABLISHED;
} // end method

string& GamePlayer::getAccountName()
{
	return accountName;
} // end method

unsigned int GamePlayer::getSystemUniqueID()
{
	return systemUniqueID;
} // end method

/*
	Assign a filename-safe identifier to this player object.

	Account Names are a primary key in the identity of a GamePlayer.
	When an account name is offered, the first assumption is that
	the same name has been used before.  The system will attempt
	to match the given name to a file in the storage medium.

	Upon match success, the secondary key (systemUniqueID)
	will be loaded in with all the previously known information.

	In the case that the account name is not matched,
	the assumption is that this is a new account.
	The system will attempt to create the account and assign an ID.
	A file is created in the storage medium at this time as well.

	There is one exception case to the above procedures.
	If the GamePlayer has a systemUniqueID when this method is invoked,
	then this operation converts into a 'rename' operation.
	The system will attempt to change the object's accountName value
	AND the name of the record in the storage medium.

	@param newName	Primary Key by which this player will be identified
					Any string that has file-name-illegal characters,
					such as dollar signs, question marks, or quotemarks,
					will be rejected.
	@throws	illegal_argument	when a rename operation attempts to assign a name
								that already exists in the storage medium
	@throws illegal_argument	when the newName parameter includes illegal characters
*/
void GamePlayer::setAccountName(string& newName)
{
	string oldName(accountName);

	if (IDENTITY_NOT_ESTABLISHED == systemUniqueID) // No old account information is being changed.
	{
		accountName = newName;
		load();
		if (IDENTITY_NOT_ESTABLISHED != systemUniqueID)
			return; // Record previously existed; is now adopted.
	}
	else // Already had an account.  Attempting a rename operation.
	{
		int successWhenZero = GamePlayerConfig::of(this).rename(newName);
		if (0 != successWhenZero)
			throw std::invalid_argument("Account name could not be changed.");
		
		accountName = newName;
		return;
	} // end if

	save();
	if (IDENTITY_NOT_ESTABLISHED == systemUniqueID)
	{
		accountName = oldName;
		throw std::invalid_argument("Account name could not be set.");
	}
} // end method

/*
	De-serialize the GamePlayer object,
	using the accountName attribute as a Primary Key
	to target a record in the storage medium.
	Uses the Boost serialization library.

	Fails silently.
	One indicator of failure is that attributes will not change
	from initial values.
*/
void GamePlayer::load()
{
	try {
		GamePlayerConfig::of(this).load();
	}
	catch(...)
	{
	} // end try
} // end method


/*
	Serialize the GamePlayer object,
	using the accountName attribute as a Primary Key
	to form a record in the storage medium.
	Uses the Boost serialization library.

	Fails silently.
	There is usually no indicator of failure unless
	the record was to be a new record.

	A record is considered new when its systemUniqueID
	is initially set to IDENTITY_NOT_ESTABLISHED.
	save() calls obtainSystemUniqueID() after it verifies
	that the storage medium will accept the new record,
	but before the contents of the new record are written.
*/
void GamePlayer::save()
{
	const int myIDBeforeSave = systemUniqueID;

	try {
		GamePlayerConfig::of(this).save();
	}
	catch(...)
	{
		if (myIDBeforeSave != systemUniqueID)
			systemUniqueID = myIDBeforeSave;
	} // end try
} // end method
